#[cfg(test)]
mod test{
    // Option impl Copy for T
    // Option will be copyable if  T  is copyable
    // Option will be non-copyable if T is non-copyable
    #[test]
    fn option_with_copyable(){
        //None
        {
            let none_u8 : Option<u8> = None;
            println!("{:?}", none_u8);

            let new_none_u8 = none_u8; //NOTE: copy action
            println!("{:?}, {:?}", none_u8, new_none_u8);
        }
        {
            let some_u8: Option<u8> = Some(1_u8);
            println!("{:?}", some_u8);

            let new_some_u8 = some_u8; //NOTE: copy action
            println!("{:?}, {:?}", some_u8, new_some_u8);
        }
    }
    #[test]
    fn option_with_copyable_match(){
        {
            let some_u8: Option<u8> = Some(1_u8);
            match some_u8 {
                None => {}
                Some(x) => {
                    println!("{:?}", x); //NOTE: copy action
                }
            }
            println!("{:?}", some_u8);
        }
    }


    
    #[test]
    fn option_with_non_copyable(){
        {
            let none_string : Option<String> = None;
            println!("{:?}", none_string);

            let new_none_string = none_string; //NOTE: move action
            //println!("{:?}, {:?}", none_string/*moved*/, new_none_string); //Compile error
            println!("{:?}", new_none_string);
        }
        {
            let some_string: Option<String> = Some("hello".to_string());
            println!("{:?}", some_string);

            let new_some_string = some_string; //NOTE: move action
            //println!("{:?}, {:?}", some_string/*moved*/, new_some_string); //Compile error
            println!("{:?}", new_some_string);
        }
    }
    #[test]
    fn option_with_non_copyable_match(){
        {
            let some_string: Option<String> = Some("hello".to_string());
            match some_string {
                None => { println!("None");}
                Some(x) => {
                    println!("{:?}", x); //NOTE: move String
                }
            }
            //Compile error! println!("{:?}", some_string);
        }
        {
            let some_string: Option<String> = Some("hello".to_string());
            match some_string { // the same as "match &some_string" // match is borrow
                None => { println!("None");}
                Some(ref x) => {
                    println!("{:?}", x); //NOTE: ref borrow String
                }
            }
            println!("{:?}", some_string);//NOTE: some string is ok
        }
        {
            let mut some_string: Option<String> = Some("hello".to_string());
            match some_string { // the same as "match &some_string" // match is borrow
                None => { println!("None");}
                Some(ref mut x) => {
                    println!("{:?}", x); //NOTE: mut borrow String
                    *x = "world".to_string();
                    println!("{:?}", x); //NOTE: mut borrow String
                }
            }
            println!("{:?}", some_string);//NOTE: some string is ok
        }
    }


    #[derive(Debug)]
    struct Object {
        val: Option<String>,
    }
    impl Object {
        fn reset(mut self) {
            if let Some(new_string) = self.val {
                println!("new string is : {new_string}");
            }
            self.val = None;
        }
    }
    #[test]
    fn option_in_struct_moved() {
        {
            let mut object = Object{ val:Some("hello".to_owned()) };

            if let Some(new_string) = object.val { //moved here, 
                println!("new string is : {new_string}");
                //cannot visit the obj.val
                //println!("can not visit object after moved value:{:?}", object);
            }

            //move new value into object.val
            object.val = None;
            println!("new value of object is : {:?}", object);
        }
        {
            let object = Object{ val:Some("hello".to_owned()) };
            object.reset();
        } 
    }
}
